////////// Main client application logic //////////

//////
////// Utility functions
//////

var player = function () {
  return Players.findOne(Session.get('player_id'));
};

var game = function () {
  var me = player();
  return me && me.game_id && Games.findOne(me.game_id);
};

var set_selected_positions = function (word) {
  var paths = paths_for_word(game().board, word.toUpperCase());
  var in_a_path = [];
  var last_in_a_path = [];

  for (var i = 0; i < paths.length; i++) {
    in_a_path = in_a_path.concat(paths[i]);
    last_in_a_path.push(paths[i].slice(-1)[0]);
  }

  for (var pos = 0; pos < 16; pos++) {
    if (_.indexOf(last_in_a_path, pos) !== -1)
      Session.set('selected_' + pos, 'last_in_path');
    else if (_.indexOf(in_a_path, pos) !== -1)
      Session.set('selected_' + pos, 'in_path');
    else
      Session.set('selected_' + pos, false);
  }
};

var clear_selected_positions = function () {
  for (var pos = 0; pos < 16; pos++)
    Session.set('selected_' + pos, false);
};

//////
////// lobby template: shows everyone not currently playing, and
////// offers a button to start a fresh game.
//////

Template.lobby.helpers({
  show: function () {
    // only show lobby if we're not in a game
    return !game();
  },

  waiting: function () {
    var players = Players.find({_id: {$ne: Session.get('player_id')},
                                name: {$ne: ''},
                                game_id: {$exists: false}});

    return players;
  },

  count: function () {
    var players = Players.find({_id: {$ne: Session.get('player_id')},
                                name: {$ne: ''},
                                game_id: {$exists: false}});

    return players.count();
  },

  disabled: function () {
    var me = player();
    if (me && me.name)
      return '';
    return 'disabled';
  }
});

var trim = function (string) { return string.replace(/^\s+|\s+$/g, ''); };

Template.lobby.events({
  'keyup input#myname': function (evt) {
    var name = trim($('#lobby input#myname').val());
    Players.update(Session.get('player_id'), {$set: {name: name}});
  },
  'click button.startgame': function () {
    Meteor.call('start_new_game');
  }
});

//////
////// board template: renders the board and the clock given the
////// current game.  if there is no game, show a splash screen.
//////
var SPLASH = ['','','','',
              'W', 'O', 'R', 'D',
              'P', 'L', 'A', 'Y',
              '','','',''];

Template.board.helpers({
  square: function (i) {
    var g = game();
    return g && g.board && g.board[i] || SPLASH[i];
  },

  selected: function (i) {
    return Session.get('selected_' + i);
  },

  clock: function () {
    var clock = game() && game().clock;

    if (!clock || clock === 0)
      return;

    // format into M:SS
    var min = Math.floor(clock / 60);
    var sec = clock % 60;
    return min + ':' + (sec < 10 ? ('0' + sec) : sec);
  }
});

Template.board.events({
  'click .square': function (evt) {
    var textbox = $('#scratchpad input');
    // Note: Getting the letter out of the DOM is kind of a hack
    var letter = evt.target.textContent || evt.target.innerText;
    textbox.val(textbox.val() + letter);
    textbox.focus();
  }
});

//////
////// scratchpad is where we enter new words.
//////

Template.scratchpad.helpers({
  show: function () {
    return game() && game().clock > 0;
  }
});

Template.scratchpad.events({
  'click button, keyup input': function (evt) {
    var textbox = $('#scratchpad input');
    // if we clicked the button or hit enter
    if ((evt.type === "click" || (evt.type === "keyup" && evt.which === 13))
        && textbox.val()) {
      var word_id = Words.insert({player_id: Session.get('player_id'),
                                  game_id: game() && game()._id,
                                  word: textbox.val().toUpperCase(),
                                  state: 'pending'});
      Meteor.call('score_word', word_id);
      textbox.val('');
      textbox.focus();
      clear_selected_positions();
    } else {
      set_selected_positions(textbox.val());
    }
  }
});

Template.postgame.helpers({
  show: function () {
    return game() && game().clock === 0;
  }
});

Template.postgame.events({
  'click button': function (evt) {
    Players.update(Session.get('player_id'), {$set: {game_id: null}});
  }
});

//////
////// scores shows everyone's score and word list.
//////

Template.scores.helpers({
  show: function () {
    return !!game();
  },

  players: function () {
    return game() && game().players;
  }
});

Template.player.helpers({
  winner: function () {
    var g = game();
    if (g.winners && _.include(g.winners, this._id))
      return 'winner';
    return '';
  },

  total_score: function () {
    var words = Words.find({game_id: game() && game()._id,
                            player_id: this._id});

    var score = 0;
    words.forEach(function (word) {
      if (word.score)
        score += word.score;
    });
    return score;
  }
});

Template.words.helpers({
  words: function () {
    return Words.find({game_id: game() && game()._id,
                       player_id: this._id});
  }
});


//////
////// Initialization
//////

Meteor.startup(function () {
  // Allocate a new player id.
  //
  // XXX this does not handle hot reload. In the reload case,
  // Session.get('player_id') will return a real id. We should check for
  // a pre-existing player, and if it exists, make sure the server still
  // knows about us.
  var player_id = Players.insert({name: '', idle: false});
  Session.set('player_id', player_id);

  // subscribe to all the players, the game i'm in, and all
  // the words in that game.
  Tracker.autorun(function () {
    Meteor.subscribe('players');

    if (Session.get('player_id')) {
      var me = player();
      if (me && me.game_id) {
        Meteor.subscribe('games', me.game_id);
        Meteor.subscribe('words', me.game_id, Session.get('player_id'));
      }
    }
  });

  // send keepalives so the server can tell when we go away.
  //
  // XXX this is not a great idiom. meteor server does not yet have a
  // way to expose connection status to user code. Once it does, this
  // code can go away.
  Meteor.setInterval(function() {
    if (Meteor.status().connected)
      Meteor.call('keepalive', Session.get('player_id'));
  }, 20*1000);
});
